/** @format */

import { onGetApi } from './env';
interface RequestConfig {
  url: string;
  method?:
    | 'GET'
    | 'POST'
    | 'PUT'
    | 'DELETE'
    | 'OPTIONS'
    | 'HEAD'
    | 'TRACE'
    | 'CONNECT';
  params?: Record<string, any>; // 路径参数
  data?: Record<string, any>; // body参数
  header?: Record<string, any>;
  timeout?: number;
  [key: string]: any;
}

interface ResponseData<T = any> {
  code: number;
  data: T;
  message: string;
}

// 请求拦截器
const requestInterceptor = (config: RequestConfig): RequestConfig => {
  // 处理路径参数
  if (config.params) {
    const queryString = Object.keys(config.params)
      .map(
        (key) =>
          `${encodeURIComponent(key)}=${encodeURIComponent(config.params![key])}`,
      )
      .join('&');

    config.url += config.url.includes('?')
      ? `&${queryString}`
      : `?${queryString}`;
    delete config.params;
  }

  // 设置默认请求头
  config.header = {
    'Content-Type': 'application/json', //'application/json;charset=UTF-8',// 'application/json',
    ...config.header,
  };

  // 添加token等认证信息
  const token = uni.getStorageSync('token');
  if (token) {
    config.header.Authorization = `Bearer ${token}`;
  }

  // 设置默认超时时间
  config.timeout = config.timeout || 10000;
  config.url = onGetApi() + config.url;
  console.log('请求拦截器:', config);
  return config;
};

// 响应拦截器
const responseInterceptor = <T = any>(
  response: UniApp.RequestSuccessCallbackResult,
): Promise<ResponseData<T>> => {
  console.log('响应拦截器:', response);

  const { statusCode, data } = response;

  // HTTP状态码检查
  if (statusCode >= 200 && statusCode < 300) {
    const responseData = data as ResponseData<T>;

    // 业务状态码检查
    if (responseData.code === 200 || responseData.code === 0) {
      return Promise.resolve(responseData);
    } else {
      // 业务错误处理
      uni.showToast({
        title: responseData.message || '请求失败',
        icon: 'none',
      });
      return Promise.reject(responseData);
    }
  } else {
    // HTTP错误处理
    let errorMessage = '网络错误';

    switch (statusCode) {
      case 401:
        errorMessage = '未授权，请重新登录';
        // 清除token并跳转到登录页
        uni.removeStorageSync('token');
        uni.reLaunch({
          url: '/pages/login/Index',
        });
        break;
      case 403:
        errorMessage = '拒绝访问';
        break;
      case 404:
        errorMessage = '请求地址不存在';
        break;
      case 500:
        errorMessage = '服务器内部错误';
        break;
      default:
        errorMessage = `请求失败 ${statusCode}`;
    }

    uni.showToast({
      title: errorMessage,
      icon: 'none',
    });

    return Promise.reject({ code: statusCode, message: errorMessage });
  }
};

// 错误拦截器
const errorInterceptor = (error: any): Promise<never> => {
  console.error('请求错误:', error);

  let errorMessage = '网络连接失败';

  if (error.errMsg) {
    if (error.errMsg.includes('timeout')) {
      errorMessage = '请求超时';
    } else if (error.errMsg.includes('fail')) {
      errorMessage = '网络连接失败';
    }
  }

  uni.showToast({
    title: errorMessage,
    icon: 'none',
  });

  return Promise.reject(error);
};

// 主要的请求函数
const request = <T = any>(config: RequestConfig): Promise<ResponseData<T>> => {
  return new Promise((resolve, reject) => {
    // 应用请求拦截器
    const processedConfig = requestInterceptor(config);

    uni.request({
      ...processedConfig,
      success: (response) => {
        responseInterceptor<T>(response).then(resolve).catch(reject);
      },
      fail: (error) => {
        errorInterceptor(error).catch(reject);
      },
    });
  });
};

// 便捷方法
const get = <T = any>(
  url: string,
  params?: Record<string, any>,
  config?: Partial<RequestConfig>,
): Promise<ResponseData<T>> => {
  return request<T>({
    url,
    method: 'GET',
    params,
    ...config,
  });
};

const post = <T = any>(
  url: string,
  data?: Record<string, any>,
  config?: Partial<RequestConfig>,
): Promise<ResponseData<T>> => {
  return request<T>({
    url,
    method: 'POST',
    data,
    ...config,
  });
};

const put = <T = any>(
  url: string,
  data?: Record<string, any>,
  config?: Partial<RequestConfig>,
): Promise<ResponseData<T>> => {
  return request<T>({
    url,
    method: 'PUT',
    data,
    ...config,
  });
};

const del = <T = any>(
  url: string,
  params?: Record<string, any>,
  config?: Partial<RequestConfig>,
): Promise<ResponseData<T>> => {
  return request<T>({
    url,
    method: 'DELETE',
    params,
    ...config,
  });
};

export { request, get, post, put, del };

export default request;
